/* eslint-disable no-console */
import { WeatherUtils } from './weather-utils.js';
import { ConfigEncryptor } from '/js/secure/config-encryptor.js';
import { SignJWT } from '/libs/jwt/js/jose-4.15.9.js';

// 浏览器兼容的算法名称
const getAlgorithm = () => {
    if (window.chrome) return {name: 'Ed25519'};
    if (window.safari) return {name: 'EdDSA', namedCurve: 'Ed25519'};
    return {name: 'NODE-ED25519'};                                    // Firefox 等
};

// JWT 管理
class JWTManager {
    static TOKEN_REFRESH_THRESHOLD = 300; // 5分钟缓冲
    static CLOCK_DRIFT_TOLERANCE = 180;   // 3分钟时钟偏差容错
    static cache = null; // 内存缓存
    static CACHE_KEY = 'jwtCache';

    static async generate(decryptedConfig) {
        const now = JWTManager.getAdjustedTime();
        const exp = now + decryptedConfig.expiration - this.TOKEN_REFRESH_THRESHOLD;

        return new SignJWT({
            sub: decryptedConfig.projectId
        })
            // Header 部分
            .setProtectedHeader({
                alg: 'EdDSA',                                     // 签名算法
                kid: decryptedConfig.credentialId,                // 凭据ID
            })
            .setIssuedAt()                                        // 签发时间，自动设置 iat 为当前时间戳
            .setExpirationTime(exp)                               // 过期时间，使用 Unix 时间戳格式
            .sign(await crypto.subtle.importKey(
                'jwk',
                decryptedConfig.privateKeyJwk,
                getAlgorithm(),                                   // 使用兼容性包装
                true,
                ['sign']
            ));
    }

    static async getJWT(decryptedConfig) {
        // 1. 检查内存缓存
        if (this.cache && !this.isExpired(this.cache)) {
            return this.cache.jwt;
        }

        // 2. 检查sessionStorage
        const stored = sessionStorage.getItem(this.CACHE_KEY);
        if (stored) {
            try {
                const parsed = JSON.parse(stored);
                if (!this.isExpired(parsed)) {
                    this.cache = parsed;
                    return parsed.jwt;
                }
            } catch (e) {
                console.warn('缓存解析失败:', e);
            }
        }

        // 3. 生成新JWT
        const jwt = await this.generate(decryptedConfig);
        const decoded = this.decodeJWT(jwt);
        const cacheData = {
            jwt,
            exp: decoded.exp // 使用JWT自带的过期时间
        };

        // 4. 更新双缓存
        this.cache = cacheData;
        sessionStorage.setItem(this.CACHE_KEY, JSON.stringify(cacheData));

        return jwt;
    }

    static getAdjustedTime() {
        return Math.floor(Date.now() / 1000) - this.CLOCK_DRIFT_TOLERANCE;
    }

    static isExpired(cacheItem) {
        return (cacheItem.exp - 30) <= Math.floor(Date.now() / 1000); // 剩余 30 秒视为过期
    }

    static decodeJWT(jwt) {
        try {
            return JSON.parse(atob(jwt.split('.')[1]));
        } catch (e) {
            console.error('JWT解码失败:', e);
            return { exp: 0 };
        }
    }
}

(async function ($) {
    const $qweather = $('#qweather');
    let retriesCount = 0;

    async function fetchWeatherWithRetry() {
        try {
            if (!window.__weatherConfig) {
                await new Promise(resolve => {
                    const timer = setTimeout(() => {
                        window.removeEventListener('weatherConfigReady', resolve);
                        throw new Error('配置加载超时');
                    }, 5000);
                    window.addEventListener('weatherConfigReady', () => {
                        clearTimeout(timer);
                        resolve();
                    });
                });
            }

            const encryptedConfig = window.__weatherConfig.getSetting();
            if (!encryptedConfig) throw new Error('天气配置加载失败');

            const password = sessionStorage.getItem('encryptionPassword');
            const decryptedConfig = await ConfigEncryptor.decrypt(encryptedConfig, password);

            // 验证 JWK
            const requiredJwkFields = ['kty', 'crv', 'd', 'x'];
            const missingFields = requiredJwkFields.filter(f => !decryptedConfig.privateKeyJwk[f]);
            if (missingFields.length > 0) {
                throw new Error(`JWK 合法: 缺失 ${missingFields.join(', ')}`);
            }

            // 生成 JWT
            const jwt = await JWTManager.getJWT(decryptedConfig);
            // console.debug('JWT信息:', jwt);

            // 调试信息
            const decoded = JWTManager.decodeJWT(jwt);
            console.debug(`[module] [jwt] 剩余 ${Math.round((decoded.exp - JWTManager.getAdjustedTime() -  JWTManager.CLOCK_DRIFT_TOLERANCE) / 60)} 分钟`, {
                生成时间: new Date(decoded.iat * 1000),
                过期时间: new Date(decoded.exp * 1000),
                本地时间: new Date()
            });

            // 获取位置
            const locationData = await WeatherUtils.getBestPossibleLocation()
            if (!locationData) {
                throw new Error('无法获取位置信息');
            }

            // API请求
            const {lat, lng} = locationData;
            const response = await fetch(`${decryptedConfig.apiEndpoint}?location=${lng},${lat}&lang=zh`, {
                headers: {Authorization: `Bearer ${jwt}`}
            });

            if (!response.ok) {
                if (response.status === 401) throw new Error('JWT 验证失败，可能是时钟不同步');
                throw new Error(`${response.status}${response.statusText ? ' - ' : ''}${response.statusText}`);
            }

            const data = await response.json();
            if (!data || !data.now) throw new Error('无效的天气数据');

            // 更新UI
            $qweather.removeClass().addClass(`qi-${data.now.icon}`);
            $qweather.attr('title', `温度: ${data.now.temp}°C | 天气: ${data.now.text} | 风向: ${data.now.windDir}`);
            $qweather.show();

            retriesCount = 0;
        }
        catch (error) {
            if (retriesCount === 3) console.error(`[module] [weather] 天气数据加载失败:`, error);
            if (retriesCount < 3) {
                retriesCount++;
                await new Promise(resolve => setTimeout(resolve, 1000));
                return fetchWeatherWithRetry();
            }
            $qweather.hide();
        }
    }

    function initWeather() {
        if ($('#qweather').length !== 0) {
            // 初始化加载（立即显示）,使用 requestIdleCallback 初始化（非阻塞）
            requestIdleCallback(fetchWeatherWithRetry);
        }
    }

    initWeather();

})(window.jQuery);